/*
 * @file gkt_window.h
 */

#ifndef GKT_WINDOW_H
#define GKT_WINDOW_H

#include "gkt_types.h"
#include "gkt_debug.h"
#include "gkt_list.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef int16_t	gkt_window_id_t;
typedef struct _gkt_window_desc	gkt_window_desc_s;
typedef struct _gkt_window	gkt_window_s;

#include "gkt_led.h"
#include "gkt_ambient_light.h"
#include "gkt_key.h"
#include "gkt_language.h"
#include "gkt_font.h"
#include "gkt_text.h"
#include "gkt_event.h"
#include "gkt_widget.h"
#include "gkt_window_system.h"
#include "gkt_window_timer.h"
#include "gkt_window_timeout.h"
#include "gkt_window_user.h"
#include "gkt_window_voice.h"

#define GKT_WINDOW_ID_PREVIOUS	-1
enum {
	GKT_WINDOW_ID_START = 0,
	GKT_WINDOW_ID_CURRENT,
	GKT_WINDOW_ID_ACTIVE,
	GKT_WINDOW_ID_USER_BASE,
};

/* minor_type of WINDOW EVENT */
enum {
	/* user event type of window event handler */
	GKT_WINDOW_INIT = 0,	/* window custom init after window object is created
							 * in this event handling, window event handler could:
							 *   1. save params passed from the previous window if exists; 
							 *   2. alloc dynamic resource scuh as memory;
							 *   3. set new attr of some widgets to replace there default settings
							 *      such as min_size and max_size of textbox.
							 *   4. other custom init operations needed;
							 */

	GKT_WINDOW_UNINIT,		/* window custom uninit before window object is destroyed
							 * in this event handling, window event handler could:
							 *   1. save result that previous window needs;
							 *   2. free dynamic resource allocated in handling INIT event;
							 *   3. other custom uninit operations needed;
							 */

	GKT_WINDOW_ACTIVE,		/* window custom active before window is showed
							 * in this event handling, window event handler could:
							 *   1. set or clear attributes of some widgets to replace there default settings,
							 *      such as showable and so on;
							 *   2. set new data of some widgets to replace there default settings;
							 */

	GKT_WINDOW_INACTIVE,	/* window custom inactive before window is hided
							 * in this event handling, window event handler could:
							 *   1. set or clear attributes of some widgets
							 *   2. other custom inactive operations needed;
							 */
	GKT_WINDOW_MAX
};

/*
 * custom window event handler prototype declare
 *
 * if major_type == GKT_EVENT_WINDOW
 *    id is ignored
 * if major_type == GKT_EVENT_WIDGET
 *    id is widget_id
 * if major_type == GKT_EVENT_KEY
 *    id is ignored
 * if major_type == GKT_EVENT_TIMER
 *    id is timer_id
 *
 * return value:
 *  GKT_EVENT_HANDLE_COMPLETE:
 *    the window event handler responses the event;
 *  GKT_EVENT_HANDLE_CONTINUE:
 *    the window event handler does not response the event
 */
typedef int (*gkt_window_event_handler)(
				uint32_t major_type, uint32_t minor_type, 
				uint32_t id, uint32_t data);

struct _gkt_window_desc {
	gkt_window_id_t id;
	uint16_t	widget_nums;
	const gkt_widget_desc_s	*widget_descs;
	const gkt_window_event_handler	event_handler;
};

#define GKT_WINDOW_F_LINKED	(1U << 0)
#define GKT_WINDOW_F_SHOW	(1U << 1)
#define GKT_WINDOW_F_ACTIVE_1ST	(1U << 2)

struct _gkt_window {
	gkt_list_s	link;

	uint32_t	flags;

	const gkt_window_desc_s	*desc;
	gkt_widget_s	*widgets;
	gkt_widget_s	*widget_focus;

#if GKT_CONFIG_VOICE_OUTPUT_ENABLE
	uint32_t	voice_id;
	uint32_t	voice_flags;
	int	voice_request_id;
#endif

	uint32_t	private_data;
};


#define __WIDGET_DESC	__SECTION(.rodata.widget.desc)
#define GKT_WINDOW_WIDGET_DESCS_DEFINE(name)	\
	static const gkt_widget_desc_s sc_window_##name##_widget_descs[] \
			__WIDGET_DESC __USED	

#define __WINDOW_DESC	__SECTION(.rodata.window.desc)
#define GKT_WINDOW_DESC_DEFINE(name)	\
	static const gkt_window_desc_s sc_window_##name##_desc \
			__WINDOW_DESC __USED = \
	{	\
		.id	= WINDOW_ID_##name,	\
		.widget_nums	= WIDGET_ID_MAX,	\
		.widget_descs	= sc_window_##name##_widget_descs,	\
		.event_handler	= window_##name##_event_handler,	\
	}

#define GKT_WINDOW_DESC_DEFINE_NO_WIDGETS(name)	\
	static const gkt_window_desc_s sc_window_##name##_desc \
			__WINDOW_DESC __USED = \
	{	\
		.id	= WINDOW_ID_##name,	\
		.widget_nums	= 0,	\
		.widget_descs	= NULL,	\
		.event_handler	= window_##name##_event_handler,	\
	}

int gkt_window_active_is_start(void);

gkt_window_s *gkt_window_find(gkt_window_id_t id);

int gkt_window_show(gkt_window_id_t id, uint32_t data);

int gkt_window_is_showed(gkt_window_id_t id);

int gkt_window_current_is_showed(void);

/*
 * @function : gkt_window_exit
 * @brief    : window exist (hide & destroyed)
 * @attention: this function should be called from user window event handler
 */
void gkt_window_exit(void);

void gkt_window_switch_control(int enable);

#if GKT_CONFIG_VOICE_OUTPUT_ENABLE
/*
 * @function : gkt_window_set_voice_id
 * @brief    : set (background) voice attr
 * @attention: 
 *   1. this function should be called from user window event handler
 *   2. if you call this function during the handling of INIT/ACTIVE event, 
 *      the voice will be played after the window is showed;
 *   3. if you call this function at other times, the voice will be
 *      played when the window is showed next time, or call function
 *      gkt_window_play_voice to achieve;
 *   4. call this function with voice_attr NULL will clear the voice;
 */
void gkt_window_set_voice(uint32_t id, uint32_t flags);
#else
#define gkt_window_set_voice(id, flags)	do { } while(0)
#endif

/*
 * @function : gkt_window_put/get_private_data
 * @brief    : put / save window private data pointer
 * @attention: this function should be called from user window event handler
 */
void gkt_window_put_private_data(uint32_t private_data);
uint32_t gkt_window_get_private_data(void);

int gkt_window_custom_event_handle(gkt_window_s *window,
				uint32_t major_type, uint32_t minor_type, 
				uint32_t id, uint32_t data);

int gkt_window_manager_init(void);

void gkt_window_manager_start(gkt_window_id_t start_window_id);

#ifdef __cplusplus
}
#endif

#endif	/* GKT_WINDOW_H */

